package com.dahuyou.tryy.too.parse.clazz.file;

import com.dahuyou.tryy.too.parse.clazz.file.classpath.Classpath;
import com.dahuyou.tryy.too.parse.clazz.file.clazzfile.ClassFile;
import com.dahuyou.tryy.too.parse.clazz.file.clazzfile.MemberInfo;
import com.dahuyou.tryy.too.parse.clazz.file.clazzfile.attributeinfo.AttributeInfo;
import com.dahuyou.tryy.too.parse.clazz.file.clazzfile.constantpool.ConstantInfo;
import com.dahuyou.tryy.too.parse.clazz.file.cmd.Cmd;

import java.util.Arrays;

/**
 * program arguments：-Xthejrepath D:\programs\javas\java1.8/jre -Xthetargetclazz D:\test\itstack-demo-jvm-master\find-class-from-classpath\target\test-classes\com\dahuyou\find\clazz\test\ShowMeByteCode
 */
public class Main {

    public static void main(String[] args) {
        Cmd cmd = Cmd.parse(args);
        if (!cmd.ok || cmd.helpFlag) {
            System.out.println("Usage: <main class> [-options] class [args...]");
            return;
        }
        if (cmd.versionFlag) {
            //注意案例测试都是基于1.8，另外jdk1.9以后使用模块化没有rt.jar
            System.out.println("java version \"1.8.0\"");
            return;
        }
        startJVM(cmd);
    }

    private static void startJVM(Cmd cmd) {
        // 创建classpath
        Classpath cp = new Classpath(cmd.thejrepath, cmd.classpath);
//        System.out.printf("classpath：%s class：%s args：%s\n", cp, cmd.getMainClass(), cmd.getAppArgs());
        System.out.printf("classpath：%s parsed class：%s \n", cp, cmd.thetargetclazz);
        //获取className
//        String className = cmd.getMainClass().replace(".", "/");
        try {
//            byte[] classData = cp.readClass(className);
            /*byte[] classData = cp.readClass(cmd.thetargetclazz.replace(".", "/"));
            System.out.println(Arrays.toString(classData));
            System.out.println("classData：");
            for (byte b : classData) {
                //16进制输出
                System.out.print(String.format("%02x", b & 0xff) + " ");
            }*/
            String clazzName = cmd.thetargetclazz.replace(".", "/");
            // 创建className对应的ClassFile对象
            ClassFile classFile = loadClass(clazzName, cp);
            printClassInfo(classFile);

        } catch (Exception e) {
            System.out.println("Could not find or load main class " + cmd.getMainClass());
            e.printStackTrace();
        }
    }

    private static void printClassInfo(ClassFile cf) {
        System.out.println("version: " + cf.majorVersion() + "." + cf.minorVersion());
        System.out.println("constants count：" + cf.constantPool().getSiz());
        ConstantInfo[] constantInfoArr = cf.constantPool().getConstantInfos();
        /*System.out.println("-------常量池信息开始------");
        for (int i = 1; i < constantInfoArr.length; i++) {
            System.out.println("常量位置：" + i);
            ConstantInfo constantInfo = constantInfoArr[i];
            if (constantInfo != null) constantInfo.showInfo();
        }
        System.out.println("-------常量池信息结束------");*/
        System.out.format("access flags：0x%x\n", cf.accessFlags());
        System.out.println("this class：" + cf.className());
        System.out.println("super class：" + cf.superClassName());
        System.out.println("interfaces：" + Arrays.toString(cf.interfaceNames()));
        System.out.println("fields count：" + cf.fields().length);
        for (MemberInfo memberInfo : cf.fields()) {
            System.out.format("字段信息：%s \t\t %s\n", memberInfo.name(), memberInfo.descriptor());
        }

        System.out.println("methods count: " + cf.methods().length);
        for (MemberInfo memberInfo : cf.methods()) {
            System.out.format("方法信息：%s \t\t %s\n", memberInfo.name(), memberInfo.descriptor());
        }

    }

    /**
     * 生成class文件对象
     * @param clazzName
     * @param cp
     * @return
     */
    private static ClassFile loadClass(String clazzName, Classpath cp) {
        try {
            // 获取类class对应的byte数组
            byte[] classData = cp.readClass(clazzName);
            return new ClassFile(classData);
        } catch (Exception e) {
            System.out.println("无法加载到类： " + clazzName);
            return null;
        }
    }

}
